﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

using System.Windows.Input;

namespace CPDPWEM.Utils
{
    /// <summary>
    /// Abstract class implementing the ICommand interface.
    /// </summary>
    public abstract class CommandBase : ICommand
    {
        public abstract void Execute(object parameter);
        public abstract bool CanExecute(object parameter);

        public event EventHandler CanExecuteChanged;

        /// <summary>
        /// Raises the CanExecuteChanged event.
        /// </summary>
        public void RaiseCanExecuteChanged()
        {
            var evnt = CanExecuteChanged;
            if (null != evnt)
                evnt(this, new EventArgs());
        }
    }

    /// <summary>
    /// Class defining a command that does not use any parameters.
    /// </summary>
    public class Command : CommandBase
    {
        /// <summary>
        /// Creates a Command that executes <paramref name="executeAction"/> and always returns
        /// true when CanExecute() is called.
        /// </summary>
        /// <param name="executeAction"></param>
        public Command(Action executeAction) : this(executeAction, null)
        {
        }

        /// <summary>
        /// Creates a command that calls <paramref name="executeAction"/> when Execute() is
        /// called and calls <paramref name="canExecuteFunc"/> when CanExecute() is called.
        /// </summary>
        /// <param name="executeAction"></param>
        /// <param name="canExecuteFunc"></param>
        public Command(Action executeAction, Func<bool> canExecuteFunc)
        {
            _executeAction = executeAction;

            if (null != canExecuteFunc)
                _canExecuteFunc = canExecuteFunc;
            else
                _canExecuteFunc = () => true;
        }

        public void Execute()
        {
            Execute(null);
        }

        public override void Execute(object obj)
        {
            if (null == _executeAction)
                throw new NotImplementedException();
            _executeAction();
        }

        public bool CanExecute()
        {
            return CanExecute(null);
        }

        public override bool CanExecute(object obj)
        {
            if (null == _canExecuteFunc)
                throw new NotImplementedException();
            return _canExecuteFunc();
        }

        Func<bool> _canExecuteFunc;
        Action _executeAction;
    }

    /// <summary>
    /// Templated class for using the ICommand interface, templated with a single parameter.
    /// </summary>
    /// <typeparam name="T">Type of parameter associated with the command.</typeparam>
    public class Command<T> : CommandBase
    {
        /// <summary>
        /// Creates a command using the given <paramref name="executeAction"/>. A default CanExecute() is defined
        /// to always return true.
        /// </summary>
        /// <param name="executeAction">Action to execute when the command is called.</param>
        public Command(Action<T> executeAction)
            : this(executeAction, null)
        {
        }

        /// <summary>
        /// Creates a command using the given <paramref name="executeAction"/> and <paramref name="canExecuteFunc"/>.
        /// </summary>
        /// <param name="executeAction">Action executed when the command is called.</param>
        /// <param name="canExecuteFunc">Predicate called to determine if the command is active. If null, a default
        /// predicate is used that always returns true.</param>
        public Command(Action<T> executeAction, Func<T, bool> canExecuteFunc)
        {
            _executeAction = executeAction;

            // If the user doesn't provide a canExecuteFunc, create our own that always returns true.
            if (null != canExecuteFunc)
                _canExecuteFunc = canExecuteFunc;
            else
                _canExecuteFunc = obj => true;
        }

        public override bool CanExecute(object parameter)
        {
            if (null == _canExecuteFunc)
                throw new NotImplementedException();
            return _canExecuteFunc((T)parameter);
        }

        public override void Execute(object parameter)
        {
            if (null == _executeAction)
                throw new NotImplementedException();
            _executeAction((T)parameter);
        }

        Func<T, bool> _canExecuteFunc;
        Action<T> _executeAction;
    }

    public abstract class BaseCommandAttribute : Attribute
    {
        public string CommandName
        {
            get { return _commandName; }
        }

        public Type ParameterType
        {
            get { return _parameterType; }
        }

        public BaseCommandAttribute(string commandName)
            : this(commandName, null)
        { }

        public BaseCommandAttribute(string commandName, Type parameterType)
        {
            _commandName = commandName;
            _parameterType = parameterType;
        }

        string _commandName;
        Type _parameterType;
    }

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class CommandExecuteAttribute : BaseCommandAttribute
    {
        public CommandExecuteAttribute(string commandName)
            : base(commandName)
        { }

        public CommandExecuteAttribute(string commandName, Type parameterType)
            : base(commandName, parameterType)
        { }
    }

    [AttributeUsage(AttributeTargets.Method, AllowMultiple=true)]
    public class CommandCanExecuteAttribute : BaseCommandAttribute
    {
        public CommandCanExecuteAttribute(string commandName)
            : base(commandName)
        { }

        public CommandCanExecuteAttribute(string commandName, Type parameterType)
            : base(commandName, parameterType)
        { }
    }
}
